/**
 * Permet la gestion d'un input autocomplete, avec possibilité de bloquage avec ID
 *
 * @author Kévin Fauconnet
 */


/**
 * Représente un élément Autocomplete de la page
 */
var AutocompleteInput = function(opts) {

	var domdiv;
	var dominput;
	var domhidden;
	var domreset;

	var source;
	var appendTo;
	var options;
	
	var disabled = false;
	
	var $this = this;
	
	var ID = {
		RESET: '.reset',
		HIDDEN: 'input[type="hidden"]',
		TEXT: 'input[type="text"]'
	};
	var PROP = {
		OPTIONS: 'AutocompleteInputOptions',
		INIT: 'AutocompleteInputInit'
	};
	var CSSCLASS = {
		DISABLED: 'blocked'
	};
	
	/**
	 * Initialisation
	 */
	function __construct(opts) {
		
		if (typeof(opts.noblock) == "undefined") {
			opts.noblock = true;
		}

		domdiv = $(opts.input);
		
		if ($(domdiv).prop(PROP.OPTIONS)) { // On récupère les options si elles ont été stockés
			options = $(domdiv).prop(PROP.OPTIONS);
			for (var i in opts) {
				options[i] = opts[i];
			}
		} else {
			options = opts;
		}
		var url = options.url;
		
		var hidden = options.hidden;
		var reset = options.reset;

		if (!reset) { // Recherche automatique du reset
			reset = $(domdiv).find(ID.RESET);
		}
		if (!hidden) { // Recherche automatique du hidden
			hidden = $(domdiv).find(ID.HIDDEN);
		}
		
		dominput = domdiv.find(ID.TEXT);

		domhidden = hidden;
		domreset = reset;
		
		// Si la source n'est pas précisé, on prends le paramètre URL
		source = options.source;
		
		if (!source && url) {
			source = url;
		}

		if (!$(domdiv).prop(PROP.INIT)) {
			initCSS();
			initEvent();
			initCSSList();			
			initState();
			$(domdiv).prop(PROP.INIT,true);
		}
		
		initAutocomplete();
		
		$(domdiv).prop(PROP.OPTIONS, options);
	};
	
	/**
	 * Initialisation du contenur de l'autococmplétion
	 */
	function initCSSList() {
		
		appendTo = "body";
		var maxWidth = options.maxWidth;
		var maxHeight = options.maxHeight;
		
		if (typeof(maxWidth) == "undefined") {
			maxWidth = $(domdiv).css("width");
		}

		// Si on a précisé une hauteur ou largeur
		if (maxWidth || maxHeight) {
			var d = document.createElement("div");
			d.style.position = "absolute";
			if (maxWidth) {
				d.style.width = maxWidth;
			}
			if (maxHeight) {
				d.style.height = maxHeight;
			}

			document.getElementsByTagName("body")[0].appendChild(d);
			appendTo = d;
		}
		options.appendTo = appendTo;
	}
	
	/** 
	 * Initialisation du CSS composant autocomplete
	 */
	function initCSS() {

		var width = parseInt($(domdiv).css("width"))-9;
		var widthDelete = 16;

		
		// Si on est en noblock, on ennleve la taille du delete et des padding, bordures, etc...
		if (options.noblock) {
			widthDelete = 0;
			width = parseInt($(domdiv).css("width"))-9;
			$(domreset).css("display","none");
		}

		$(dominput).css("width",(width - widthDelete)+"px");

	}

	
	/**
	 * Initialise l'autocomplete sur l'input text
	 */
	function initAutocomplete() {
		var extraParams = options.extraParams;
		var highlight = options.highlight;
		var dblclickforall = options.dblclickforall;
		var minLength = options.minLength;
		var noblock = options.noblock;
		var callbackSelect = options.select;
		var unselect = options.unselect;
		
		if (typeof(highlight) !== "boolean") {
			highlight = false;
		}
		
		// Si on veut une URL + des extraParams, on est obligé de redéfinir la source
		if (typeof(source) == "string" && typeof(extraParams) != "undefined")
		{
			var _url = source;
			source = function(request, response) {
				var _extraParams = extraParams;
				if (typeof(extraParams) == "function") { // Exécution de la fonction, si les paramètres sont dynamiques
					_extraParams = extraParams(request.term);
				}
				_extraParams.term = request.term;
				$.getJSON(_url, _extraParams, response);
			};
		}
		
		// Automatiquement 0 si double clic pour tout récupérer
		if (dblclickforall) {
			minLength = 0;
		} else if (typeof(minLength) == "undefined") {
			minLength = 1;
		}
		
		// Ajout de l'autocomplete
		$(dominput).autocomplete({
			source: source,
			select: onSelectAutocomplete,
			highlight: highlight,
			appendTo: options.appendTo,
			minLength: minLength,
			noblock: options.noblock
		});
	}

	/**
	 * Initialisation des évènements d'un input autocomplete non multiple
	 */
	function initEvent() {
		
		var noblock = options.noblock;
		var dblclickforall = options.dblclickforall;
		
		// Initialisation des évènements et rafraichissement de ce qui est visible
		if (!noblock) {
			$(domreset).click(onUserReset);
		}
		
		if (dblclickforall) {
			$(dominput).dblclick(onDblClickForAll);
		}
	}
	
	/**
	 * Initialise l'état du composant
	 * Dans un cas simple:
	 * - Vérouillage de l'autocomplete si c'est un non noblock, et que le hidden et input sont renseignés
	 * - Suppression du texte si c'est un non noblock et qu'aucune val dans hidden est renseigné
	 */
	function initState() {

		if (!options.noblock) {
			var input = dominput;
			var hidden = domhidden;
			
			if ($(input).val() != "" && $(hidden).val() != "") {
				$this.lock();
				$(input).attr('title',$(input).val());
			}
			else if ($(input).val() != "") {
				$(input).val("");
			}
		}
	}
	
	/**
	 * Evènement à la sélection d'un élément dans la liste d'autocomplete
	 */
	function onSelectAutocomplete(event, ui) {
	
		var callbackSelect = options.select;
		var noblock = options.noblock;
		
		$(domhidden).val(ui.item.id);
		$(dominput).attr('title',ui.item.value);
		
		if (!noblock)
			$this.lock();


		if (typeof(callbackSelect) == "function")
		{
			var ret = callbackSelect(ui.item);
			if (typeof(ret) == "boolean" && !ret)
				return false;
		}
	};
	
	/**
	 * Evènement au clic sur le bouton "reset"
	 */
	function onUserReset() {
		var unselect = options.unselect;
		
		$this.unlock();

		if (typeof(unselect) == "function") {
			unselect();
		}
	};
	
	/**
	 * Evènement au double clic sur l'input, pour rechercher tous les éléments
	 */
	function onDblClickForAll() {
		$(dominput).autocomplete( "search", "" );
	};
	
	
	/**
	 * Rafraichit l'autocomplete: si les input sont remplit, le lock est ajouté, et inversement
	 */
	this.refresh = function() {
		var div = $(domdiv);
		var input = $(dominput);
		var hidden = $(domhidden);
		var reset = $(domreset);
		
		var noblock = options.noblock;
		
		if (!noblock && $(input).val() != "" && $(hidden).val() != "") {
			$this.lock();
			$(input).attr('title',$(input).val());
		} else if (!noblock) {
			$this.unlock();
		}
	};
	
	/**
	 * Change la source de l'autocomplete
	 */
	this.changeSource = function(newSource) {
		var tinput = $(dominput);
		tinput.autocomplete("option","source",newSource);
	};

	/**
	 * Remet à zéro l'autocomplete
	 */
	this.reset = function() {
		$this.unlock();
	};
	
	/**
	 * Change le texte dans l'input de l'autocomplete
	 */
	this.setText = function(value) {
		$(dominput).val(value);
	};
	
	/**
	 * Déverouille le champ input et enlève la croix de suppression
	 */
	this.unlock = function() {

		$(dominput).val("");
		$(dominput).attr('title',""); // {1.09}
		$(dominput).removeClass(CSSCLASS.DISABLED);
		$(dominput).attr("readonly", false);
		$(dominput).attr("contenteditable",true);
		$(dominput).focus();
		$(domhidden).val("");
		$(domreset).css('visibility','hidden');
		$(domdiv).removeClass(CSSCLASS.DISABLED);

		
	};

	/**
	 * Verouille le champ input et affiche la croix de suppression
	 */
	this.lock = function() {
		$(domreset).css('visibility','visible');
		$(dominput).attr("readonly",true);
		$(dominput).attr("contenteditable",false);
		$(domdiv).addClass(CSSCLASS.DISABLED);
	};

	/**
	 * Désactive l'autocomplete
	 */
	this.disable = function() {

		$(dominput).attr("readonly",true);
		$(dominput).attr("contenteditable",false);
		$(domdiv).addClass(CSSCLASS.DISABLED);
		$(domreset).css('visibility','hidden');			

	};

	/**
	 * Active l'autocomplete
	 */
	this.enable = function() {
		
		var div = $(domdiv);
		var input = $(dominput);
		var reset = $(domreset);
		var hidden = $(domhidden);

		input.attr("readonly", false);
		input.attr("contenteditable",true);
		div.removeClass(CSSCLASS.DISABLED);
		
		if (input.val() != "" && hidden.val() != "") {
			
			$this.lock();
			input.attr('title',input.val());
		}
		
		disabled = false;
	};

	/**
	 * Focus l'autocomplete
	 */
	this.focus = function() {
		$(dominput).focus();
	};
	
	this.getDiv = function() {
		return $(domdiv);
	}
	
	this.getInputText = function() {
		return $(dominput);
	}
		
	/** 
	 * Récupère la valeur du texte d'un autocomplete
	 */
	this.getText = function() {
		return $(dominput).val();
	};

	/**
	 * Renvoie la valeur du champ hidden d'un autocomplete non multiple
	 */
	this.getHiddenValue = function() {
		return $(domhidden).val();
	};
	
	
	/** 
	 * Récupère la valeur de l'autocomplete d'un autocomplete non multiple
	 * Si l'autocomplete est 'noblock', la valeur du texte renvoyé, sinon celle du hidden
	 */
	this.getValue = function() {
		var val = $this.getHiddenValue();
		if (options.noblock) {
			val = $this.getText();
		}
		return val;
	};
	
	/**
	 * Change les options d'un input autocomplete
	 */
	this.setOptions = function(opts) {
		if (!opts.input) {
			opts.input = options.input;
		}
		__construct(opts);
	};

	__construct(opts);
	

};

AutocompleteInput.get = function(selector) {
	return new AutocompleteInput({input: selector});
};
AutocompleteInput.init = function(selector, options) {
	options.input = selector;
	return new AutocompleteInput(options);
};

/**
 * Ré-écrit la méthode _renderItem pour mettre en surbrillance
 * la recherche saisie et _resizeMenu pour changer la taille du menu
 */
$(document).ready(function() {
	if ($.ui && $.ui.autocomplete) {
		$.ui.autocomplete.prototype._renderItem = function( ul, item) {
			var t = item.label;
			var highlight = $(this.element).autocomplete("option", "highlight");
			if (highlight)
			{
				var regex = new RegExp("("+$.ui.autocomplete.escapeRegex(this.term)+")","gi");
				t = t.replace(regex,'<span class="ui-autocomplete-highlight">$1</span>');
			}
			return $( "<li></li>" )
				.data( "item.autocomplete", item )
				.append( $( "<a></a>" ).html( t ) )
				.appendTo( ul );

		};
		$.ui.autocomplete.prototype._resizeMenu = function() {
			var ul = this.menu.element;
			ul.outerWidth( ul.parent().outerWidth() );
			// ul.outerHeight( ul.parent().outerHeight() );
		};
	}
	
	var autocomplete = $(".autocomplete");
	for (var i = 0; i < autocomplete.length; i++) {
		var elem = $(autocomplete[i]);
		var url = elem.attr("url");
		if (url && url.length > 0) {
			AutocompleteInput.init(elem, {url: url});
		}
	}
	
	
});
